﻿using System;
using System.Collections.Concurrent;
using System.Collections.Specialized;
using System.Configuration;
using System.Text;
using System.Web;

namespace NappiSite.EasyCache
{
    public static class Cache
    {
        private static readonly ICacheProvider cache = new CacheFactory().GetCache();
        private static readonly int defaultExpirationSeconds = GetDefaultExpirationSeconds();

        private static int GetDefaultExpirationSeconds()
        {
            var config = ConfigurationManager.GetSection("easyCacheSettings") as NameValueCollection;
            if (config != null)
            {
                int seconds;
                var value = config["defaultExpirationSeconds"];
                if (int.TryParse(value, out seconds))
                {
                    return seconds;
                }

            }
            return 0;
        }

 
        public static string GetCacheKey(string cacheKey,params object[] args)
        {
            var keyBuilder = new StringBuilder();
            keyBuilder.AppendFormat("ez_{0}", cacheKey);
            foreach(var arg in args)
            {
                keyBuilder.AppendFormat("_{0}", arg);
            }
            return keyBuilder.ToString();
        }

        public static void Add(string cacheKey, object objectToCache)
        {
           Add(cacheKey,objectToCache,0);
        }

        public static void Add(string cacheKey, object objectToCache, int expirationSeconds)
        {
            if (objectToCache == null)
            {
                Remove(cacheKey);
                return;
            }

            if (expirationSeconds <= 0) expirationSeconds = defaultExpirationSeconds;

            if (expirationSeconds > 0)
            {
                cache.Insert(cacheKey, objectToCache, DateTime.Now.AddSeconds(expirationSeconds));
            }
            else
            {
                cache.Insert(cacheKey, objectToCache);
            }
        }

        public static bool Exists(string cacheKey)
        {
            return Get(cacheKey) != null;
        }

        public static bool Exists<T>(string cacheKey) where T : class
        {
            var obj = Get(cacheKey) as T;

            return (obj != null);
        }

        public static void Remove(string cacheKey)
        {
            cache.Remove(cacheKey);
        }


        public static object Get(string cacheKey)
        {
            return cache[cacheKey];
        }

        private static readonly ConcurrentDictionary<string, object> cacheLocks = new ConcurrentDictionary<string, object>();
        public static T Get<T>(string cacheKey, Func<T> method)
        {
            
            var obj = Get(cacheKey);

            if (obj == null)
            {
                lock (cacheLocks.GetOrAdd(cacheKey, new object()))                
                {
                    obj = Get(cacheKey);

                    if (obj == null)
                    {
                        obj = method.Invoke();
                        Add(cacheKey, obj);
                    }
                }
            }

            return (T) obj;
        }

    }
}